package Client.PokerClient.src;

import java.io.*;
import java.net.*;

import javax.swing.DefaultListModel;
import javax.swing.JOptionPane;

/**
 * Klasa bedeca watkiem sluzaca do obslugiwania polaczenia z serwerem.
 * @author Artur Smolibowski
 */
public class GameThread extends Thread {

  /** Gniazdo serwera. */
  private Socket server = null;
  /** Strumien wejscia. */
  private BufferedReader in = null;
  /** Strumien wyjscia. */
  private PrintWriter out = null;
  /** Zmienna przechowujac dane przeslane przez serwer.  */
  private String line = "";
  /** Zmienna boolowska okreslajaca czy nawiazano polaczenie. */
  private boolean isConnected=false;
  /**
   * Referencja do klasy glownej programu.
   */
  private Client client;
  /**
   * Zmienna przechowujaca ostatni komunikat wyslany przez server.
   */
  private String lastServerMessage;
  /**
   * Klasa obslugujaca komunikaty wysylane przez klienta z gry do servera.
   */
  private ClientGTaskController clientGTaskController;
  /**
   * Klasa obslugujaca komunikaty wysylane przez klienta z lobby do servera.
   */
  private ClientSTaskController clientSTaskController;
  /**
   * Klasa obslugujaca komunikaty wysylane przez server wczasie gry do klienta.
   */
  private ServerGTaskController serverGTaskController;
  /**
   * Klasa obslugujaca komunikaty wysylane przez server wczasie uzytkowania lobby do klienta.
   */
  private ServerSTaskController serverSTaskController;

  /**
   * Konstruktor domyslny klasy.
   * @param client Referencja do klasy glownej programu.
   */
  public GameThread(Client client) {
    this.client=client;
    lastServerMessage="";
  }

  /**
   * Funckja sluzaca do pobierania danych od serwera i wysylania ich do odpowienich klas.
   */
  private void listenSocket() {
    if(isConnected) {

      int bladOdczytu=0;
      while(isConnected == true) {
        String line="";

        try {
          line = in.readLine();
          System.out.println(line+" KONIEC");
          lastServerMessage = line;
          String tmp=line;
          if(tmp.substring(0,1).equals("S")) {
            tmp=tmp.substring(tmp.indexOf("_")+1);
            try{ tmp=tmp.substring(0, tmp.indexOf("_")); } catch(StringIndexOutOfBoundsException e) {}
            switch(tmp) {
              case "REFRESH": serverSTaskController.S_REFRESH(line);
                              break;
              case "CREATE":  serverSTaskController.S_CREATE(line);
                              break;
              case "ID":      serverSTaskController.S_ID(line);
                              break;
              case "ERROR":   serverSTaskController.S_ERROR(clientSTaskController.getLastTask());
                              break;
            }
          }
          else if(tmp.substring(0,1).equals("G")) {
            tmp=tmp.substring(tmp.indexOf("_")+1);
            try{ tmp=tmp.substring(0, tmp.indexOf("_")); } catch(StringIndexOutOfBoundsException e) {}
            switch(tmp) {
              case "PLAYERJOIN": serverGTaskController.G_PLAYERJOIN(line);
                                 break;
              case "PLAYEROUT":  serverGTaskController.G_PLAYEROUT(line);
                                 break;
              case "CARDS":      serverGTaskController.G_CARDS(line);
                                 break;
              case "BALL":       serverGTaskController.G_BALL(line);
                                 break;
              case "ALL":        serverGTaskController.G_ALL(line);
                                 break;
              case "ERROR":      serverGTaskController.G_ERROR(clientGTaskController.getLastTask());
                                 break;
            }
          }
        }
        catch (IOException e) {
          bladOdczytu++;
          if(bladOdczytu>10) {
            finalize();
            System.out.println("Zerwano polaczenie, watek: "+this.getName());
          }
        }
      }
    }
  }

  /**
   * Funkcja sluzaca do zakonczenia polaczenia miedzy kilientem a serwerem
   */
  public void finalize() {
    try {
      out.println("S_DISCONNECT");
      server.close();
      in.close();
      out.close();
      line=null;
      isConnected=false;
    } 
    catch (IOException e) {
      System.out.println("Mozliwe ze nie zostaly zamkniete wszystkie strumienie, watek: "+this.getName());
    }
  }
  /**
   * Metoda zluzaca do nawiazania polaczenia z serwerem.
   * @param ServerAdress Adres serwera.
   * @param Port Port serwera.
   */
  public void ConnectToServer(String ServerAdress, String Port) {
    try {
      server = new Socket();
      server.connect(new InetSocketAddress(ServerAdress, Integer.parseInt(Port)), 2000);
      out = new PrintWriter(server.getOutputStream(), true);
      in = new BufferedReader(new InputStreamReader(server.getInputStream()));

      clientGTaskController = new ClientGTaskController(client, out);
  	  clientSTaskController = new ClientSTaskController(client, out);
  	  serverGTaskController = new ServerGTaskController(client);
  	  serverSTaskController = new ServerSTaskController(client);

  	  isConnected=true;
      client.CreateServerWindow();
      client.getServerWindow().ChangeWindow();
      if(!this.isAlive()) this.start();
    }
    catch (NumberFormatException e) {
      JOptionPane.showMessageDialog(null, "Port nie jest liczba");
    }
    catch (UnknownHostException e) {
      JOptionPane.showMessageDialog(null, "Nieznany host: "+ServerAdress);
    }
    catch  (IOException e) {
      JOptionPane.showMessageDialog(null, "Nieznaleziono serwera");
    }
  }

  /**
   * Funkcja wykonywany po wystartowaniu watku
   */
  public void run() {
    while(true) {
      listenSocket();
    }
  }
  /**
   * Pobranie klasy obslugujacej komunikaty gracza do serwera w czasie gry.
   * @return Klasa obslugujaca komunikaty gracza do serwera w czasie gry
   */
  public ClientGTaskController getClientGTaskController() {
    return clientGTaskController;
  }
  /**
   * Pobranie klasy obslugujacej komunikaty gracza do serwera w czasie uzytkowania lobby.
   * @return Klasa obslugujaca komunikaty gracza do serwera w czasie uzytkowania lobby
   */
  public ClientSTaskController getClientSTaskController() {
    return clientSTaskController;
  }
  /**
   * Pobranie ostatniego komunikatu wyslaniego przez serwer.
   * @return
   */
  public String getLastServerMessage() {
    return lastServerMessage;
  }
  /**
   * Pobranie klasy obslugujacej komunikaty przeslane przez serwer wczasie gry.
   * @return Klasa obslugujaca komunikaty przeslane przez serwer wczasie gry.
   */
  public ServerGTaskController getServerGTaskController() {
    return serverGTaskController;
  }
  /**
   * Pobranie klasy obslugujacej komunikaty przeslane przez serwer wczasie uzytkowania lobby.
   * @return Klasa obslugujaca komunikaty przeslane przez serwer wczasie uzytkowania lobby.
   */
  public ServerSTaskController getServerSTaskController() {
	return serverSTaskController;
  }
  /**
   * Sprawdza czy klient jest polaczony.
   * @return Czy klient jest polaczony z serwerem.
   */
  public boolean isConnected() {
    return isConnected;
  }
}